#include <algorithm>
#include <iterator>

#include <QScriptEngine>

#include "qtprojectgeneratorfactory.h"
#include "settings.h"

#include "symbian/symbiandefines.h"
#include "symbian/symbianqtprojectgenerator.h"

#include "maemo5/maemo5defines.h"
#include "maemo5/maemo5qtprojectgenerator.h"

#include "rcsymbian/rcsymbianqtprojectgenerator.h"

#include "rcmaemo5/rcmaemo5qtprojectgenerator.h"

/**
  * This anonymous namespace is the configuration
  * for the "static plugin" types that implement platform specific
  * project generation.
  */
namespace
{
    IQtProjectGenerator * LocalSymbianPGCtor(QString               /* platformId */,
                                             GeneratorOutputView & outputView,
                                             QObject             * parent)
    {
        IQtProjectGenerator
            * rv = new SymbianQtProjectGenerator(outputView,
                                                 parent);

        return rv;
    }


    IQtProjectGenerator * LocalMaemo5PGCtor(QString               /* platformId */,
                                            GeneratorOutputView & outputView,
                                            QObject             * parent)
    {
        IQtProjectGenerator
                * rv = new Maemo5QtProjectGenerator(outputView,
                                                    parent);

        return rv;
    }


    IQtProjectGenerator * RemoteSymbianPGCtor(QString               platformId,
                                              GeneratorOutputView & outputView,
                                              QObject             * parent)
    {
        IQtProjectGenerator
             * rv = new RcSymbianQtProjectGenerator(platformId,
                                                    outputView,
                                                    parent);

        return rv;
    }


    IQtProjectGenerator * RemoteMaemo5PGCtor(QString               platformId,
                                             GeneratorOutputView & outputView,
                                             QObject             * parent)
    {
        IQtProjectGenerator
             * rv = new RcMaemo5QtProjectGenerator(platformId,
                                                   outputView,
                                                   parent);

        return rv;
    }


    typedef IQtProjectGenerator * (PGCtor)(QString, GeneratorOutputView &, QObject *);

    const PlatformInfo PLATFORMINFOS[] = {
        { SYMBIAN_PLATFORMNAME,
          SYMBIAN_SHORTDESC,
          DYN_BUILDTARGET SYMBIAN_PLATFORMNAME,
          true,
          reinterpret_cast<void*>(&LocalSymbianPGCtor)
        }
#if 0 // Disable local maemo compilation
        ,
        { MAEMO5_PLATFORMNAME,
          MAEMO5_SHORTDESC,
          DYN_BUILDTARGET MAEMO5_PLATFORMNAME,
          false,
          reinterpret_cast<void*>(&LocalMaemo5PGCtor)
        }
#endif
    };
}


QtProjectGeneratorFactory::QtProjectGeneratorFactory()
{
    using namespace std;

    // Local, hardwired compilation environments
    copy(PLATFORMINFOS,
         PLATFORMINFOS + sizeof(PLATFORMINFOS)/sizeof(PlatformInfo),
         back_inserter(m_supportedPlatforms));

    // Check for remote, dynamically configured compilation environments
    QScriptEngine
        scriptEngine;
    Settings::OsDescMap
        osDescMap = Settings::RcOSes(scriptEngine);
    if (osDescMap.size() == 0)
        return;
    Settings::OsQtPairList
        osQtPairs = Settings::RcOsQtPairs(scriptEngine);

    foreach (Settings::OsQtPair osQtPair, osQtPairs)
    {
        PlatformInfo
            pi;

        if (osQtPair.m_os.indexOf("s60_") == 0)
        {
            pi.m_opaque = reinterpret_cast<void*>(&RemoteSymbianPGCtor);
        }
        else if (osQtPair.m_os.indexOf("maemo5") == 0)
        {
            pi.m_opaque = reinterpret_cast<void*>(&RemoteMaemo5PGCtor);
        }
        else
        {
            continue;
        }

        pi.m_platformName = "RC %1, Qt %2";
        pi.m_platformName = pi.m_platformName.arg(osQtPair.m_os, osQtPair.m_qt);
        pi.m_platformName = pi.m_platformName.replace('_', '.');

        pi.m_shortDescription = "Remote Compiling for ";
        pi.m_shortDescription += osDescMap[osQtPair.m_os];
        pi.m_shortDescription += " with Qt v";
        pi.m_shortDescription += osQtPair.m_qt;
        pi.m_platformName = pi.m_platformName.replace('_', '.');

        // The platform id shall be the prefix with the wccParams concatenated
        // to it.
        pi.m_platformId = "%1%2";
        pi.m_platformId = pi.m_platformId.arg(DYN_BUILDTARGET,
                                              osQtPair.wccParams());

        pi.m_isDefault = false;

        m_supportedPlatforms.push_back(pi);
    }
}


QList<PlatformInfo> QtProjectGeneratorFactory::supportedPlatforms() const
{
    QList<PlatformInfo>
        rv(m_supportedPlatforms);

    return rv;
}

IQtProjectGenerator *
QtProjectGeneratorFactory::createProjectGenerator(const QString       & platformId,
                                                  GeneratorOutputView & outputView,
                                                  QObject             * parent) const
{
    IQtProjectGenerator
        * rv = NULL;

    QList<PlatformInfo>::const_iterator
        it = m_supportedPlatforms.begin(),
        end = m_supportedPlatforms.end();

    for (; it != end; ++it)
    {
        if (it->m_platformId == platformId)
        {
            PGCtor
                * ctor = reinterpret_cast<PGCtor*>(it->m_opaque);

            rv = (*ctor)(platformId,
                         outputView,
                         parent);
            break;
        }
    }

    return rv;
}
